package m

import (
	"fmt"
	"sort"
	"sync"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"

	"GameServer/Common/utils"
	"GameServer/Game/cache"
	"GameServer/Game/dbmodule"
	"GameServer/Game/errors"
)

var (
	tableName string = "userActRanks"
)

// 每一个玩家的排名
type UserActRank struct {
	Uid         string `bson:"uid" json:"uid"`
	Name        string `bson:"name" json:"name"`
	Head        string `bson:"head" json:"head"`
	AvatarFrame int64  `bson:"avatarFrame" json:"avatarFrame"`
	Item        int64  `bson:"item" json:"item"`
	LastRankId  int64  `bson:"lastRankId" json:"lastRankId"`
	RankId      int64  `bson:"rankId" json:"rankId"`
	IsRobot     int64  `bson:"isRobot" json:"isRobot"` // 0-是机器人
}

// 单个分组的排名
type ActRankGroup struct {
	BaseM
	ActId               int64                   `bson:"actId" json:"actId"`                             // 活动id
	RewardId            int64                   `bson:"rewardId" json:"rewardId"`                       // 奖励配表id
	GroupId             int64                   `bson:"groupId" json:"groupId"`                         // 组号
	HasRobot            int64                   `bson:"hasRobot" json:"hasRobot"`                       // 该组是否有机器人 0-有 1-无
	UserActRankGroup    map[string]*UserActRank `bson:"userActRankGroup"`                               // 用户排名
	SnapShotTime        int64                   `bson:"snapShotTime" json:"snapShotTime"`               // 快照时间
	SendRewardTimeStamp map[int64]int64         `bson:"sendRewardTimeStamp" json:"sendRewardTimeStamp"` // 派发奖励时间记录 key-派发零点时间戳 value-派发实际时间
	rw                  *sync.RWMutex
}

// 用户就排名
type OldUserActRank struct {
	Uid        string   `bson:"_id"`        // 用户uid
	RecordTime int64    `bson:"recordTime"` // 快照时间
	GroupId    int64    `bson:"groupId"`    // 组号
	State      int64    `bson:"state"`      // 0.未领取 1.奖励已领取
	ResGoods   []BaseKV `bson:"resGoods"`   // 排名奖励
}

func NewActRankGroup() cache.EntryI {
	return &ActRankGroup{
		UserActRankGroup: make(map[string]*UserActRank, 0),
		rw:               new(sync.RWMutex),
	}
}

// 保存快照
func (arG *ActRankGroup) TakeSnapShot() (err error) {
	arG.SnapShotTime = utils.TNow().Unix()
	err = dbmodule.MgoDB.GameDB.Upsert(fmt.Sprintf("%s_snapShot", tableName), bson.M{"groupId": arG.GroupId}, arG)
	if err != nil {
		return
	}
	return
}

// 保存信息
func (arG *ActRankGroup) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert(tableName, bson.M{"groupId": arG.GroupId}, arG)
	if err != nil {
		return
	}
	return
}

func (arG *ActRankGroup) Load(key interface{}) (err error) {
	switch key.(type) {
	case int64:
		arG.GroupId = key.(int64)
	default:
		log.WithFields(log.Fields{
			"method": "activity_rank_Load",
			"data":   key,
		}).Error("无效的key load")
		return errors.New("无效的key load")
	}
	return arG.LoadData()
}

// 加载数据
func (arG *ActRankGroup) LoadData() (err error) {
	err = dbmodule.MgoDB.GameDB.FindOne(tableName, bson.M{"groupId": arG.GroupId}, nil, &arG)
	if err != nil {
		if err.Error() == "not found" {
			return err
		}
		return err
	}
	// if arG.UserActRankGroup == nil {
	// 	arG.UserActRankGroup = make(map[string]*UserActRank, 0)
	// }
	return
}

// 更新数据
func (arG *ActRankGroup) Update(val *ActRankGroup) {
	Cache.Put(tableName, arG.GroupId, val) //arG.GroupId.Hex()
	val.UpdateData()
}

// 删除分组
func (arG *ActRankGroup) Delete() (err error) {
	Cache.Remove(tableName, arG.GroupId)
	return dbmodule.MgoDB.GameDB.Remove(tableName, bson.M{"groupId": arG.GroupId})
}

func (arG *ActRankGroup) RWLock() *sync.RWMutex {
	if arG.rw == nil {
		arG.rw = new(sync.RWMutex)
	}
	return arG.rw
}

func (u *User) GetActRankGroup() (arG *ActRankGroup) {
	// v1, ok := Cache.Get("user", u.Uid.Hex())
	// getUser := v1.(*User)
	// fmt.Printf("[m.activity_rank]玩家[%s]从缓存中得到Group[%d],直接获得Group[%d]\n", u.Name, getUser.UserGroup, u.UserGroup)
	v, ok := Cache.Get(tableName, u.UserGroup)
	if ok == false {
		return nil
	}
	r := v.(*ActRankGroup)
	return r
}

func GetActRankGroupByGroupId(groupId int64) (arG *ActRankGroup) {
	v, ok := Cache.Get(tableName, groupId)
	if ok == false {
		return nil
	}
	r := v.(*ActRankGroup)
	if r.UserActRankGroup == nil {
		r.UserActRankGroup = make(map[string]*UserActRank, 0)
		r.Update(r)
	}
	return r
}

func (u *User) CreateActRankGroup(actId int64, rankRewardId int64) (arG *ActRankGroup) {
	listAccept := make([]*ActRankGroup, 0)
	err := dbmodule.MgoDB.GameDB.FindAll(tableName, nil, nil, &listAccept)
	if err != nil {
		return
	}
	var GroupId int64 = int64(len(listAccept))
	GroupId = (GroupId + 1)
	arG = &ActRankGroup{
		ActId:            actId,
		RewardId:         rankRewardId,
		GroupId:          GroupId,
		HasRobot:         1,
		UserActRankGroup: make(map[string]*UserActRank),
	}
	// arG.Save()
	arG.Update(arG)
	return arG
}

func (arG *ActRankGroup) GetMember(uid string) (r *UserActRank, ok bool) {
	arG.RWLock().RLock()
	r, ok = arG.UserActRankGroup[uid]
	arG.RWLock().RUnlock()
	return
}

// 尝试用机器人填充用户列表，至上限
func (arG *ActRankGroup) TryFillUpMemberWithRobot(actTurn int64, offsetTime int64, robots []*User) {
	arG.RWLock().RLock()
	for idx, item := range robots {
		orgItem := utils.GetSlotActRobotOrgItemNum(actTurn, offsetTime, int64(idx))
		fadeUid := fmt.Sprintf("robot%d%d", arG.GroupId, idx)
		arG.UserActRankGroup[fadeUid] = &UserActRank{
			Uid:         fadeUid,
			Name:        item.Name,
			Head:        item.Head,
			AvatarFrame: item.AvatarFrame,
			Item:        orgItem,
			LastRankId:  0,
			RankId:      0,
			IsRobot:     0, // 标识为机器人
		}
	}
	arG.HasRobot = 0 // 标识该组含有机器人
	arG.Update(arG)

	arG.RWLock().RUnlock()
	return
}

func (arG *ActRankGroup) AddMember(uMember *UserActRank) (err error) {
	defer arG.Update(arG)
	arG.RWLock().Lock()
	arG.UserActRankGroup[uMember.Uid] = uMember
	arG.RWLock().Unlock()
	return
}

func (arG *ActRankGroup) AddItem(uid string, addNum int64) (rankId int64) {
	arG.RWLock().Lock()
	data, ok := arG.UserActRankGroup[uid]
	if ok {
		data.Item = (data.Item + addNum)
		arG.UserActRankGroup[uid] = data
	}
	arG.RWLock().Unlock()
	if ok {
		rankId = arG.ReSort(uid)
	}
	return
}

func (arG *ActRankGroup) MemberList() (r map[string]*UserActRank) {
	r = make(map[string]*UserActRank, 0)
	arG.RWLock().RLock()
	for k, v := range arG.UserActRankGroup {
		r[k] = v
	}
	arG.RWLock().RUnlock()
	return r
}

func (arG *ActRankGroup) DelMember(uid string) (err error) {
	defer arG.Update(arG)
	arG.RWLock().RLock()
	if _, ok := arG.UserActRankGroup[uid]; ok {
		delete(arG.UserActRankGroup, uid)
	}
	arG.RWLock().RUnlock()
	return
}

func (arG *ActRankGroup) RobotAutoAdd() {
	if arG.HasRobot == 0 {
		defer arG.Update(arG)
		arG.RWLock().RLock()
		for _, v := range arG.UserActRankGroup {
			if v.IsRobot == 0 {
				v.Item = (v.Item + utils.RandomInt64(2, 12))
			}
		}
		arG.ReSort("")
		arG.RWLock().RUnlock()
	}
}

func (arG *ActRankGroup) RobotAutoAdd_ByTurn(turn int64) {
	if arG.HasRobot == 0 {
		defer arG.Update(arG)
		arG.RWLock().RLock()
		var index int64 = 0
		for _, v := range arG.UserActRankGroup {
			if v.IsRobot == 0 {
				var FinalAddNum int64 = utils.GetSlotActRobotAutoAddItemNum(turn, index)
				v.Item = (v.Item + FinalAddNum)
				index = index + 1
			}
		}
		arG.ReSort("")
		arG.RWLock().RUnlock()
	}
}

func (arG *ActRankGroup) ReSort(uid string) (rankId int64) {
	UserGroup := make([]*UserActRank, 0)
	arG.RWLock().RLock()
	for _, user := range arG.UserActRankGroup {
		UserGroup = append(UserGroup, user)
	}
	// 对分数进行排序
	sort.Slice(UserGroup, func(i, j int) bool {
		if UserGroup[i].Item == UserGroup[j].Item {
			return UserGroup[i].LastRankId < UserGroup[j].LastRankId
		} else {
			return UserGroup[i].Item > UserGroup[j].Item
		}
	})
	arG.UserActRankGroup = make(map[string]*UserActRank, 30)
	var rank int64 = 0
	// var lastItemNum int64 = -1 // 是否允许相同排名
	for _, data := range UserGroup {
		rank = (rank + 1)
		// if lastItemNum == data.Item {
		// 	rank = (rank - 1)
		// }
		// lastItemNum = data.Item
		data.RankId = rank
		data.LastRankId = rank
		arG.UserActRankGroup[data.Uid] = data
	}
	arG.Update(arG)
	if val, ok := arG.UserActRankGroup[uid]; ok {
		rankId = val.RankId
	}
	// arG.Save()
	arG.RWLock().RUnlock()

	return
}

func ActRankSort() {

}

// func GetUserRanks() (r []*UserRank) {
// 	v, _ := Cache.Get("rank", "rank")
// 	r = v.(*Rank).UserRanks
// 	if len(r) > 100 {
// 		r = r[:100]
// 	}
// 	return
// }

func GetOldActRankGroup(groupId int64) (group *ActRankGroup, err error) {
	group = &ActRankGroup{
		GroupId: groupId,
	}
	err = dbmodule.MgoDB.GameDB.FindOne(fmt.Sprintf("%s_snapShot", tableName), bson.M{"groupId": group.GroupId}, nil, &group)
	if err != nil {
		return
	}
	return
}

func GetOldUserActRank(uid string) (oldUserActRank *OldUserActRank, err error) {
	oldUserActRank = &OldUserActRank{
		Uid:      uid,
		ResGoods: make([]BaseKV, 0),
	}
	err = dbmodule.MgoDB.GameDB.FindOne("OldUserActRank", bson.M{"_id": uid}, nil, &oldUserActRank)
	return
}

func (this *OldUserActRank) Save() (err error) {
	err = dbmodule.MgoDB.GameDB.Upsert("OldUserActRank", bson.M{"_id": this.Uid}, this)
	if err != nil {
		return
	}
	return
}
